package com.qfedu.service.impl;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.qfedu.dao.*;
import com.qfedu.pojo.entity.Permission;
import com.qfedu.pojo.entity.Role;
import com.qfedu.pojo.entity.User;
import com.qfedu.pojo.entity.UserRole;
import com.qfedu.pojo.req.UserReq;
import com.qfedu.pojo.req.UserRoleReq;
import com.qfedu.pojo.resp.BasePerDataResp;
import com.qfedu.pojo.resp.BasePerValueResp;
import com.qfedu.pojo.resp.BaseResp;
import com.qfedu.service.AdminService;
import com.qfedu.utils.MD5Utils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

@Service
public class AdminServiceImpl implements AdminService {

    @Autowired
    AdminRepository adminRepository;

    @Autowired
    AdminMapper adminMapper;

    @Autowired
    RoleRepository roleRepository;

    @Autowired
    UserRoleRepository userRoleRepository;

    @Autowired
    UserRoleMapper userRoleMapper;


    @Override
    public BaseResp login(UserReq userReq) {
        //1.将后台传入的用户名和密码存入token中
        UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken(userReq.getUserName(), userReq.getPassword());
        //2.通过安全管理器工厂获取到shiro的主体
        Subject subject = SecurityUtils.getSubject();
        try {
            //3.通过主体进行登录操作
            subject.login(usernamePasswordToken);
        } catch (UnknownAccountException unknownAccountException) {
            return new BaseResp(0, "管理员不存在！", null, null);
        } catch (IncorrectCredentialsException incorrectCredentialsException) {
            return new BaseResp(0, "密码错误！", null, null);
        }
        return new BaseResp(1, "登录成功！", null, null);
    }

    @Override
    public BaseResp findAllAdmin(Integer page, Integer size) {
        //1.在执行全查之前开启分页
        PageHelper.startPage(page, size);
        //2.执行全查操作
        List<User> users = adminMapper.findAllAdmin();
        //3.将查询结果放入分页对象中完成分页操作
        PageInfo<User> adminPageInfo = new PageInfo<>(users);
        return new BaseResp(1, "查询成功", adminPageInfo.getList(), adminPageInfo.getTotal());
    }

    @Override
    public BaseResp isAuthenticated() {
        Subject subject = SecurityUtils.getSubject();
        if(subject.isAuthenticated()) {
            return new BaseResp(1, "success", subject.getPrincipal(), null);
        }
        return new BaseResp().Error();
    }

    @Override
    public BaseResp addOrUpdAdmin(UserReq userReq) {
        //1.将收参实体类中的内容复制到数据库实体类中
        User user = new User();
        //将AdminReq中接收的请求参数复制到admin实体类中
        BeanUtils.copyProperties(userReq, user);
        //2.将后台页面传入的密码直接设置为密文
        String md5 = MD5Utils.createMd5(userReq.getUserName(), userReq.getPassword());
        //3.判断用户传入的id是否为空
        if(userReq.getId() != null) { //不为空则说明与执行的是修改操作
            //3.1通过拿到的ID去数据库中查询出用户信息
            Optional<User> adminRepositoryById = adminRepository.findById(userReq.getId());
            //由于返回的类型为Optional，所以需要一个Admin对象来接参
            User user1 = adminRepositoryById.get();   //将获取到的参数传给Admin对象
            //4.判断加密后的密文是否与数据库中的密码一致
            if(!md5.equals(user1.getPassword())) {    //比对不一致的情况
                user.setPassword(md5);
            }
            //6.保存到数据库
            adminRepository.saveAndFlush(user);
        } else {
            //5.说明id为空，也就是执行力新增操作
            //直接将密文设置到数据库中
            user.setPassword(md5);
            adminMapper.insertAdmin(user);
        }
        //7.返回信息
        return new BaseResp(1, "更新成功！", null, null);
    }

    @Override
    public BaseResp delAdmin(UserReq userReq) {
        adminRepository.deleteById(userReq.getId());
        return new BaseResp(1, "更新成功！", null, null);
    }

    /**
     * 该方法做三件事：
     *1.查询出全部的角色信息
     *2.查询出用户所拥有的角色id
     *3.将查询出的两个结果分别封装在两个集合中并最终封装在BasePerValueResp返回值实体中
     * @param id
     * @return
     */
    @Override
    public BaseResp findAllRoleAndAdminRole(int id) {
        //1.查询出全部的权限信息
        List<Role> roles = roleRepository.findAll();

        //定义BasePerDataResp集合，将查询到的信息全部遍历放入BasePerDataResp集合中
        List<BasePerDataResp> perData = new ArrayList<>();
        for (Role li: roles
        ) {
            //定义BasePerDataResp对象，因为每遍历一次都要一个新的对象存储查询到的权限信息
            BasePerDataResp basePerDataResp = new BasePerDataResp();
            basePerDataResp.setKey(li.getId());
            basePerDataResp.setLabel(li.getRoleName());
            //代表权限可以被选中
            basePerDataResp.setDisabled(false);
            perData.add(basePerDataResp);
        }
        //2.查询出角色所拥有的权限id
        List<Integer> perValue = roleRepository.selectRoleIdByUserId(id);
        //3.将查询出的两个结果分别封装在两个集合中并最终封装在BasePerValueResp返回值实体中
        //该实体中存放的是所有权限信息以及角色所拥有的权限id
        BasePerValueResp basePerValueResp = new BasePerValueResp();
        basePerValueResp.setData(perData);
        basePerValueResp.setValue(perValue);
        return new BaseResp(1, "success", basePerValueResp, null);
    }

    /**
     * 该方法用于向管理员授予角色操作
     * 该方法作两件事：
     * 1.通过用户id去中间表中查询该管理员是否拥有角色
     * 2.如果管理员拥有角色则清空该用户在中间表中建立的所有关联关系然后建立新的关系，如果没有角色则直接建立新的关联关系
     * @param userRoleReq   前端传入的管理员（用户表）id以及角色id集合都放在该类中
     * @return
     */
    @Override
    public BaseResp updAdminRole(UserRoleReq userRoleReq) {
        //首先从RolePermissionReq类中获取两个参数
        //用户ID
        Integer userId = userRoleReq.getUserId();
        //角色id的集合
        List<Integer> roleIdList = userRoleReq.getRoleIdList();
        //1.通过用户id去中间表中查询该用户是否拥有角色
        List<UserRole> userRoles = userRoleRepository.findByuserId(userId);
        //2.判断用户是否拥有角色
        if(userRoles != null) { //说明用户有角色
            //清空用户原来的信息，即清空用户与角色直接的绑定关系,通过用户id删除绑定关系
            userRoleMapper.deleteUserRole(userId);
        }
        //用户没有角色绑定的情况
        //建立新的用户与角色的关联关系，前提是角色的集合必须不为空的情况下
        if(roleIdList != null && roleIdList.size() > 0) {
            //将角色id和权限的id传入，建立新的绑定关系
            userRoleMapper.insertUserRole(userRoleReq);
        }
        return new BaseResp(1, "角色授予成功！", null, null);
    }

    @Override
    public BaseResp logout() {
        Subject subject = SecurityUtils.getSubject();
        subject.logout();
        return new BaseResp().Success();
    }
}
